
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "gps_data.h"

// 辅助函数：将 GPS 格式的坐标转换为十进制格式
float convertToDecimal(float coord, char direction)
{
    int degrees = (int)(coord / 100.0f);
    float minutes = coord - degrees * 100.0f;
    float decimal = degrees + minutes / 60.0f;
    
    // 如果是南纬或西经，取负值
    if (direction == 'S' || direction == 'W') {
        decimal = -decimal;
    }
    
    return decimal;
}

// 辅助函数：解析时间
void parseTime(char* timeStr, time_t* timeOut)
{
    if (timeStr == NULL || strlen(timeStr) < 6) {
        return;
    }
    
    struct tm tm_time = {0};
    
    // 从字符串中解析时分秒
    tm_time.tm_hour = atoi(timeStr) / 10000;
    tm_time.tm_min = (atoi(timeStr) / 100) % 100;
    tm_time.tm_sec = atoi(timeStr) % 100;
    
    // 获取当前日期（GPS 数据通常只提供时间部分）
    time_t now = time(NULL);
    struct tm* currentTime = localtime(&now);
    tm_time.tm_year = currentTime->tm_year;
    tm_time.tm_mon = currentTime->tm_mon;
    tm_time.tm_mday = currentTime->tm_mday;
    
    *timeOut = mktime(&tm_time);
}

// 辅助函数：解析日期
void parseDate(char* dateStr, time_t* dateOut)
{
    if (dateStr == NULL || strlen(dateStr) < 6) {
        return;
    }
    
    struct tm tm_date = {0};
    time_t now = time(NULL);
    struct tm* currentTime = localtime(&now);
    
    // 从字符串中解析日月年
    int day = atoi(dateStr) / 10000;
    int month = (atoi(dateStr) / 100) % 100;
    int year = 2000 + (atoi(dateStr) % 100);
    
    tm_date.tm_year = year - 1900;
    tm_date.tm_mon = month - 1;
    tm_date.tm_mday = day;
    tm_date.tm_hour = currentTime->tm_hour;
    tm_date.tm_min = currentTime->tm_min;
    tm_date.tm_sec = currentTime->tm_sec;
    
    *dateOut = mktime(&tm_date);
}

// 解析 GGA 句子
void parseGGASentence(char* buffer, GGAData* data)
{
    if (buffer == NULL || data == NULL) {
        return;
    }
    
    char* token = strtok(buffer, ",");
    if (token == NULL || strcmp(token, "$GPGGA") != 0) {
        return;
    }
    
    // UTC 时间
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        parseTime(token, &data->utcTime);
    }
    
    // 纬度
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->latitude = atof(token);
    }
    
    // 纬度方向
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->latitude = convertToDecimal(data->latitude, token[0]);
    }
    
    // 经度
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->longitude = atof(token);
    }
    
    // 经度方向
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->longitude = convertToDecimal(data->longitude, token[0]);
    }
    
    // 定位质量
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->fixQuality = atoi(token);
    }
    
    // 卫星数量
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->numSatellites = atoi(token);
    }
    
    // HDOP
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->hdop = atof(token);
    }
    
    // 海拔高度
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->altitude = atof(token);
    }
    
    // 海拔单位
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->altitudeUnit = token[0];
    }
    
    // 大地水准面高度
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->geoidHeight = atof(token);
    }
    
    // 大地水准面单位
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->geoidUnit = token[0];
    }
    
    printf("GGA 数据解析结果：\n");
    printf("  纬度：%f\n", data->latitude);
    printf("  经度：%f\n", data->longitude);
    printf("  定位质量：%d\n", data->fixQuality);
    printf("  卫星数量：%d\n", data->numSatellites);
    printf("  HDOP：%f\n", data->hdop);
    printf("  海拔高度：%f %c\n", data->altitude, data->altitudeUnit);
    printf("  大地水准面高度：%f %c\n\n", data->geoidHeight, data->geoidUnit);
}

// 解析 RMC 句子
void parseRMCSentence(char* buffer, RMCData* data)
{
    if (buffer == NULL || data == NULL) {
        return;
    }
    
    char* token = strtok(buffer, ",");
    if (token == NULL || strcmp(token, "$GPRMC") != 0) {
        return;
    }
    
    // UTC 时间
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        parseTime(token, &data->utcTime);
    }
    
    // 状态
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->status = (token[0] == 'A');
    }
    
    // 纬度
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->latitude = atof(token);
    }
    
    // 纬度方向
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->latitude = convertToDecimal(data->latitude, token[0]);
    }
    
    // 经度
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->longitude = atof(token);
    }
    
    // 经度方向
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->longitude = convertToDecimal(data->longitude, token[0]);
    }
    
    // 速度（节）
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->speed = atof(token);
    }
    
    // 航向
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->course = atof(token);
    }
    
    // 日期
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        parseDate(token, &data->date);
    }
    
    // 磁偏角
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->magneticVar = atof(token);
    }
    
    // 磁偏角方向
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->varDirection = token[0];
    }
    
    printf("RMC 数据解析结果：\n");
    printf("  状态：%s\n", data->status ? "有效" : "无效");
    printf("  纬度：%f\n", data->latitude);
    printf("  经度：%f\n", data->longitude);
    printf("  速度：%f 节\n", data->speed);
    printf("  航向：%f 度\n\n", data->course);
}

// 解析 GSA 句子
void parseGSASentence(char* buffer, GSAData* data)
{
    if (buffer == NULL || data == NULL) {
        return;
    }
    
    char* token = strtok(buffer, ",");
    if (token == NULL || strcmp(token, "$GPGSA") != 0) {
        return;
    }
    
    // 模式
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->mode = token[0];
    }
    
    // 定位类型
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->fixType = atoi(token);
    }
    
    // 卫星 PRN 号（最多 12 颗卫星）
    for (int i = 0; i < 12; i++) {
        token = strtok(NULL, ",");
        if (token != NULL && strlen(token) > 0) {
            data->satellites[i] = atoi(token);
        } else {
            data->satellites[i] = 0;
        }
    }
    
    // PDOP
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->pdop = atof(token);
    }
    
    // HDOP
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->hdop = atof(token);
    }
    
    // VDOP
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->vdop = atof(token);
    }
    
    printf("GSA 数据解析结果：\n");
    printf("  模式：%c\n", data->mode);
    printf("  定位类型：%d (1=无定位, 2=2D, 3=3D)\n", data->fixType);
    printf("  使用的卫星：");
    for (int i = 0; i < 12; i++) {
        if (data->satellites[i] > 0) {
            printf("%d ", data->satellites[i]);
        }
    }
    printf("\n  PDOP：%f\n", data->pdop);
    printf("  HDOP：%f\n", data->hdop);
    printf("  VDOP：%f\n\n", data->vdop);
}

// 解析 GSV 句子
void parseGSVSentence(char* buffer, GSVData* data)
{
    if (buffer == NULL || data == NULL) {
        return;
    }
    
    char* token = strtok(buffer, ",");
    if (token == NULL || strcmp(token, "$GPGSV") != 0) {
        return;
    }
    
    // 总消息数
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->totalMessages = atoi(token);
    }
    
    // 当前消息号
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->messageNumber = atoi(token);
    }
    
    // 可见卫星总数
    token = strtok(NULL, ",");
    if (token != NULL && strlen(token) > 0) {
        data->totalSatellites = atoi(token);
    }
    
    printf("GSV 数据解析结果：\n");
    printf("  消息 %d/%d：可见卫星总数 %d\n\n", 
           data->messageNumber, data->totalMessages, data->totalSatellites);
}

// 主解析函数
void parseGPSData(char* buffer, int length) 
{
    if (length < 6) {
        printf("无效的 GPS 数据\n");
        return;
    }
    
    // 创建缓冲区副本，因为 strtok 会修改原始数据
    char bufferCopy[1024];
    if (length > (int)(sizeof(bufferCopy) - 1)) {
        length = (int)(sizeof(bufferCopy) - 1);
    }
    memcpy(bufferCopy, buffer, length);
    bufferCopy[length] = '\0';
    
    // 检查消息类型
    char* sentenceType = strtok(bufferCopy, ",");
    if (sentenceType == NULL) {
        return;
    }
    
    // 根据消息类型调用相应的解析函数
    if (strcmp(sentenceType, "$GPGGA") == 0) {
        GGAData ggaData = {0};
        // 重置缓冲区副本用于重新解析
        memcpy(bufferCopy, buffer, length);
        bufferCopy[length] = '\0';
        parseGGASentence(bufferCopy, &ggaData);
    } 
    else if (strcmp(sentenceType, "$GPRMC") == 0) {
        RMCData rmcData = {0};
        // 重置缓冲区副本用于重新解析
        memcpy(bufferCopy, buffer, length);
        bufferCopy[length] = '\0';
        parseRMCSentence(bufferCopy, &rmcData);
    } 
    else if (strcmp(sentenceType, "$GPGSA") == 0) {
        GSAData gsaData = {0};
        // 重置缓冲区副本用于重新解析
        memcpy(bufferCopy, buffer, length);
        bufferCopy[length] = '\0';
        parseGSASentence(bufferCopy, &gsaData);
    } 
    else if (strcmp(sentenceType, "$GPGSV") == 0) {
        GSVData gsvData = {0};
        // 重置缓冲区副本用于重新解析
        memcpy(bufferCopy, buffer, length);
        bufferCopy[length] = '\0';
        parseGSVSentence(bufferCopy, &gsvData);
    } 
    else {
        printf("不支持的 GPS 句子类型：%s\n", sentenceType);
    }
}

// 主函数，用于测试
int main() {
    // 测试 GGA 句子解析
    char ggaData[] = "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47";
    printf("===== 解析 GGA 句子 =====\n");
    parseGPSData(ggaData, sizeof(ggaData));
    
    // 测试 RMC 句子解析
    char rmcData[] = "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A";
    printf("===== 解析 RMC 句子 =====\n");
    parseGPSData(rmcData, sizeof(rmcData));
    
    // 测试 GSA 句子解析
    char gsaData[] = "$GPGSA,A,3,04,05,09,12,20,22,24,27,30,31,32,3.2,2.5,1.9*35";
    printf("===== 解析 GSA 句子 =====\n");
    parseGPSData(gsaData, sizeof(gsaData));
    
    // 测试 GSV 句子解析
    char gsvData[] = "$GPGSV,3,1,12,04,75,285,28,05,12,023,25,09,73,162,36,12,45,205,33*75";
    printf("===== 解析 GSV 句子 =====\n");
    parseGPSData(gsvData, sizeof(gsvData));
    
    return 0;
}